﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Build.Framework;
using AbstraX.Contracts;
using Events = AbstraX.BuildEvents;
using AbstraX;

namespace CodeGenerationPipeline
{
    public class EventSourceDispatcher : IList<IEventSource>
    {
        private IEventsService eventsService;
        private List<IEventSource> eventSourceList;
        private string sourceName;

        public EventSourceDispatcher(IEventsService eventsService, string sourceName)
        {
            this.eventsService = eventsService;
            this.sourceName = sourceName;

            eventSourceList = new List<IEventSource>();
        }

        private void RemoveListeners(IEventSource eventSource)
        {
            eventSource.BuildFinished -= (sender, e) =>
            {
            };

            eventSource.BuildStarted -= (sender, e) =>
            {
            };

            eventSource.CustomEventRaised -= (sender, e) =>
            {
            };

            eventSource.ErrorRaised -= (sender, e) =>
            {
            };

            eventSource.MessageRaised -= (sender, e) =>
            {
            };

            eventSource.ProjectFinished -= (sender, e) =>
            {
            };

            eventSource.ProjectStarted -= (sender, e) =>
            {
            };

            eventSource.StatusEventRaised -= (sender, e) =>
            {
            };

            eventSource.TargetFinished -= (sender, e) =>
            {
            };

            eventSource.TargetStarted -= (sender, e) =>
            {
            };

            eventSource.TaskFinished -= (sender, e) =>
            {
            };

            eventSource.TaskStarted -= (sender, e) =>
            {
            };

            eventSource.WarningRaised -= (sender, e) =>
            {
            };
        }

        private void AddListeners(IEventSource eventSource)
        {
            eventSource.AnyEventRaised += (sender, e) =>
            {
            };

            eventSource.BuildFinished += (sender, e) =>
            {
                var args = new Events.BuildFinishedEventArgs();

                args.Read(e);

                eventsService.PostMessage(Message.BuildFinished, args);
            };

            eventSource.BuildStarted += (sender, e) =>
            {
                var args = new Events.BuildStartedEventArgs();

                args.Read(e);

                eventsService.PostMessage(Message.BuildStarted, args);
            };

            eventSource.CustomEventRaised += (sender, e) =>
            {
                var args = new Events.CustomBuildEventArgs();

                args.Read(e);

                eventsService.PostMessage(Message.CustomEventRaised, args);
            };

            eventSource.ErrorRaised += (sender, e) =>
            {
                var args = new Events.BuildErrorEventArgs();

                args.Read(e);

                eventsService.PostMessage(Message.ErrorRaised, args);
            };

            eventSource.MessageRaised += (sender, e) =>
            {
                var args = new Events.BuildMessageEventArgs();

                args.Read(e);

                eventsService.PostMessage(Message.MessageRaised, args);
            };

            eventSource.ProjectFinished += (sender, e) =>
            {
                var args = new Events.ProjectFinishedEventArgs();

                args.Read(e);

                eventsService.PostMessage(Message.ProjectFinished, args);
            };

            eventSource.ProjectStarted += (sender, e) =>
            {
                var args = new Events.ProjectStartedEventArgs();

                args.Read(e);

                eventsService.PostMessage(Message.ProjectStarted, args);
            };

            eventSource.StatusEventRaised += (sender, e) =>
            {
                var args = new Events.BuildStatusEventArgs();

                args.Read(e);

                eventsService.PostMessage(Message.StatusEventRaised, args);
            };

            eventSource.TargetFinished += (sender, e) =>
            {
                var args = new Events.TargetFinishedEventArgs();

                args.Read(e);

                eventsService.PostMessage(Message.TargetFinished, args);
            };

            eventSource.TargetStarted += (sender, e) =>
            {
                var args = new Events.TargetStartedEventArgs();

                args.Read(e);

                eventsService.PostMessage(Message.TargetStarted, args);
            };

            eventSource.TaskFinished += (sender, e) =>
            {
                var args = new Events.TaskFinishedEventArgs();

                args.Read(e);

                eventsService.PostMessage(Message.TaskFinished, args);
            };

            eventSource.TaskStarted += (sender, e) =>
            {
                var args = new Events.TaskStartedEventArgs();

                args.Read(e);

                eventsService.PostMessage(Message.TaskStarted, args);
            };

            eventSource.WarningRaised += (sender, e) =>
            {
                var args = new Events.BuildWarningEventArgs();

                args.Read(e);

                eventsService.PostMessage(Message.WarningRaised, args);
            };
        }

        public int IndexOf(IEventSource item)
        {
            return eventSourceList.IndexOf(item);
        }

        public void Insert(int index, IEventSource item)
        {
            eventSourceList.Insert(index, item);

            AddListeners(item);
        }

        public void RemoveAt(int index)
        {
            RemoveListeners(this[index]);

            eventSourceList.RemoveAt(index);
        }

        public IEventSource this[int index]
        {
            get
            {
                return eventSourceList[index];
            }
            set
            {
                eventSourceList[index] = value;
            }
        }

        public void Add(IEventSource item)
        {
            eventSourceList.Add(item);

            AddListeners(item);
        }

        public void Clear()
        {
            eventSourceList.ForEach(e => RemoveListeners(e));

            eventSourceList.Clear();
        }

        public bool Contains(IEventSource item)
        {
            return eventSourceList.Contains(item);
        }

        public void CopyTo(IEventSource[] array, int arrayIndex)
        {
            eventSourceList.CopyTo(array, arrayIndex);
        }

        public int Count
        {
            get 
            {
                return eventSourceList.Count;    
            }
        }

        public bool IsReadOnly
        {
            get 
            {
                return false;
            }
        }

        public bool Remove(IEventSource item)
        {
            RemoveListeners(item);

            return eventSourceList.Remove(item);
        }

        public IEnumerator<IEventSource> GetEnumerator()
        {
            return eventSourceList.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return eventSourceList.GetEnumerator();
        }
    }
}
